#ifndef BMC_H
#define	BMC_H

#include <stdint.h>
#include "../List.h"
#include "BMCIR.h"
#include "HMC.h"

 #ifdef __cplusplus
 extern "C" {
 #endif 

#define BMC_INITIAL_INSTR        0x100
#define BMC_STEP_INSTR           0x100

#define BMCL_INITIAL_SIZE        0x10
#define BMCL_STEP                0x10

typedef enum BMCInstructionType{
    BMCIT_Branch,
    BMCIT_Arithmetic,
    BMCIT_Logic,
    BMCIT_Memory,
    BMCIT_Jump,
    BMCIT_Other,
    BMCIT_None
}BMCInstructionType;
     
typedef enum BMCBranchInfo{
    BMCBI_TargetInSameBMC = 0x01
} BMCBranchInfo;
    
typedef struct BMCBranchInstructionInfo{
    uint16_t    Target;
    uint32_t     BranchFlags;
} BMCBranchInstructionInfo;
     
//ADT: BMCInstruction
//Describes 6502 machine instruction. This should provide
//as much information as possible for the JIT compiler in the
//translation state.
typedef struct {
    uint16_t Addr;
    uint8_t Opcode;
    uint8_t Size;
    uint8_t Operands[2];
    
    BMCInstructionType InstructionType;      //this is only needed when
                                             //accessing InstructionInformation
    union {
        BMCBranchInstructionInfo *BranchInfo;
    } InstructionInformation;
    
} BMCInstruction;

typedef struct BMCEntryPoint {
    uint8_t Data;
    struct BMCEntryPoint **Children;
} BMCEntryPoint;

//ADT: BMC - Block of Machine Code
//Describes a DBT translation unit.
typedef struct {
    uint16_t StartAddr;
    uint16_t Length;
    uint16_t Position;
    uint16_t InstructionBufferLength;
    BMCEntryPoint* EntryPoints;
    uint32_t JobFlags;                //indicates what's supposed to be done with this BMC: Translated, Update Instruction Map
    BMCInstruction** Instructions;
    BMCIR* IR;
    HMC* CompleteECTXTUnoptimized;
    HMC* PartialECTXTUnoptimized;
    uint32_t BlockSize;         //The size of this block in 6502 machine code
    uint32_t Pure;
    uint32_t Cycles;            //How many 6502 cycles in this BMC. This is only valid if Pure=1.
    uint32_t ContextsOptimized;
} BMC;

//Blocks of Machine Code Job Flags
enum BMCJF{
    BMCJF_Translate = 0x01,     //This block should be translated
    BMCJF_UpdateIM  = 0x02      //A Instruction Map update must be made
};

//ADT: BMCList - List of ready-to-translate blocks of machine code
typedef struct{
    BMC** Blocks;
    List* AnalyzeBlocks;
    uint16_t Pos, Length;
} BMCList;

//Operations for BMCBranchInstructionInfo
BMCBranchInstructionInfo* BMCBIFNew(uint16_t TargetAddress, uint32_t Info);

//Operations for BMCInstruction
BMCInstruction* BMCINew(uint16_t Address, uint8_t Opcode, uint8_t Size, BMCInstructionType InstructionType, uint8_t Operand1, uint8_t Operand2);

//Operations for BMC
BMC*        BMCNew(uint16_t StartingAddress);
void        BMCAddInstruction(BMC *Block, BMCInstruction *Instruction);
void        BMCAddEntryPoint(BMC* Block, uint16_t EntryAddress);
uint8_t     BMCSearchEntryPoint(BMC* Block, uint16_t EntryAddress);
void        BMCSetJobFlags(BMC* Block, uint32_t Flags);
void        BMCAddJobFlags(BMC* Block, uint32_t Flags);
uint32_t    BMCGetJobFlags(BMC* Block);
void        BMCEPDump(BMC *Block);
void        BMCEPExecute(BMC *Block, void (*fn)(uint16_t, void*), void* Args);

//Operations for BMCList
BMCList*               BMCLNew();
void                   BMCLAdd(BMCList* List, BMC* Block);
uint32_t               BMCLNumBlocks(BMCList* List);
BMC*                   BMCLGetBlock(BMCList* List, uint32_t BlockId);
void                   BMCLDestroy(BMCList* List);

#ifdef __cplusplus
 }
#endif

#endif	/* BMC_H */
